<?php
namespace app\data_magic\logic;

use think\Db;
use app\data_magic\data\Action;
use app\data_magic\data\Table;
use app\data_magic\data\Scene;
use app\data_magic\data\Field;
use app\data_magic\data\Filter;
use app\data_magic\struct\Input;
use app\data_magic\struct\Result;

/**
 * 解释器
 * 用来解释执行结构、场景、操作的设置
 */
class Interpreter
{
    /**
     * 访问权限控制
     * @var string $user_id 用户ID
     * @var array $roles 角色列表
     * @param string $user_id 用户ID
     * @param array $roles 角色列表
     * @return Interpreter
     */
    public $user_id="";
    public $roles=[];
    public function access($user_id,$roles=[])
    {
        $this->user_id=$user_id;
        $this->roles=$roles;
        return $this;
    }

    /**
     * 加载操作设置
     * @var Result $result 结果
     * @param string $id 操作ID
     * @return Result|false
     */
    public function loadAction($id)
    {
        $result=new Result();
        $result->userId=$this->user_id;
        $result->roles=$this->roles;
        $action_data=Db::table("dm_action")->where(["id"=>$id])->find();
        if(!$action_data){
            $this->error="未定义的操作";
            return false;
        }
        $action=new Action($action_data);
        $result->action=$action;
        if($action->bind_action){
            $result->bindAction=Db::table("dm_action")->where("id = ".$action->bind_action)->find();
        }
        if($action->link_action){
            $result->linkActions=Db::table("dm_action")->where("id in (".$action->link_action.")")->select();
        }
        if($action->bind_filter){
            $result->filters=Filter::loadFilterList($action->bind_filter);
        }
        
        $table_data=Db::table("dm_table")->where(["id"=>$action->table_id])->find();
        if(!$table_data){
            $this->error="未定义的表";
            return false;
        }
        $table=new Table($table_data);
        $result->table=$table;
        $field_list=Field::loadFieldList($action->table_id);

        $scene_data=Db::table("dm_scene")->where(["id"=>$action->scene_id])->find();
        if(!$scene_data){
            $this->error="未定义的场景";
            return false;
        }
        $scene=new Scene($scene_data);
        $result->scene=$scene;
        $readable=explode(",",$scene->readable);
        $writable=explode(",",$scene->writable);
        $required=explode(",",$scene->required);
        foreach($field_list as $index => $field){
            $field_id=$field->id;
            $field->readable=in_array($field_id,$readable);
            $field->writable=in_array($field_id,$writable);
            $field->required=in_array($field_id,$required);

            if($field_id===$table->primary_key_field){
                $result->primaryKey=$field->name;
            }
            if($field_id===$table->user_id_field){
                $result->userIdField=$field->name;
            }
            if($field_id===$table->create_time_field){
                $result->createTimeField=$field->name;
            }
            if($field_id===$table->update_time_field){
                $result->updateTimeField=$field->name;
            }
        }
        $result->fields=$field_list;
        return $result;
    }

    /**
     * 分发操作
     * @param Input $input 输入值
     * @return Result
     */
    public function dispath($result,$input){
        $list_logic=new DataList($this,$input,$result);
        $result=$list_logic->dispath();
        if($result!==false){
            return $result;
        }

        $action=$this->action;
        $data_type=$action->action["data_type"];
        if($data_type==="single"){
            $action->dataTypeSingle($input->pks);
        }
        elseif($data_type==="multi"){
            $action->dataTypeMulti($input->pks);
        }
        elseif($data_type==="where"){
            $action->dataTypeWhere($input->filter);
        }
        $action->input=$input->data;

        $target_type=$action->action["target_type"];
        if($target_type==="relate"){
            return $this->relate($action);
        }
        elseif(in_array($target_type,["show","form"])){
            return $this->page($action);
        }
        else{
            return $this->exec($action);
        }
    }
    /**
     * 跳转到关联的操作，并且传递一些参数
     * 忽略action_type,实际使用的是绑定的操作的参数
     * 忽略data_type,只能是single
     * @param Action $action 操作
     */
    public function relate($action)
    {
        $action_result=new Result();
        $action_result->is_page=false;
        if($action->action["data_type"] !== "single"){
            $action_result->status=false;
            $action_result->message="数据关联设置错误";
            return $action_result;
        }
        $item=$action->find();
        $params=$action->action["params"];
        $params=explode(";",$params);
        $new_params=[];
        foreach($params as $param){
            $param_part=explode(":",$param);
            if(count($param_part)===2){
                list($old_name,$new_name)=$param_part;
                if(isset($item[$old_name])){
                    $new_params[$new_name]=$item[$old_name];
                }
            }
        }
        $action_result->status=true;
        $action_result->redirect_params=$new_params;
        return $action_result;
    }
    /**
     * 创建数据前读取预先设置的参数
     * 比如用户id和通过URL传递的关联的数据的id
     * 并且将这些数据设置为不可编辑状态
     */
    public function getPresetBeforeCreate($action)
    {
        $item=$action->input;
        $keys=array_keys($item);
        if($action->scene->user_id_field){
            $item[$action->scene->user_id_field]=$action->user_id;
            $keys[]=$action->scene->user_id_field;
        }
        foreach($action->scene->fields as $index=>$field){
            if(in_array($field["name"],$keys)){
                $action->scene->fields[$index]["writable"]=false;
            }
        }
        return $item;
    }
}
